package com.lagou.homework.stage2.no2;

import java.util.Scanner;
import java.util.regex.Pattern;

/**
 * 第二题：
 * 编程实现控制台版并支持两人对战的五子棋游戏。
 * （1）绘制棋盘 - 写一个成员方法实现
 * （2）提示黑方和白方分别下棋并重新绘制棋盘 - 写一个成员方法实现。
 * （3）每当一方下棋后判断是否获胜 - 写一个成员方法实现。
 * （4）提示： 采用二维数组来模拟并描述棋盘，棋盘如下：
 */
public class GobangGame {

    // 成员变量，存放棋盘信息
    private String[][] boardInfos = new String[17][17];

    public String[][] getBoardInfos() {
        return boardInfos;
    }
    public void setBoardInfos(String[][] boardInfos) {
        this.boardInfos = boardInfos;
    }

    /**
     * 绘制棋盘
     */
    public void drawBoard(){
        // 1.将初始棋盘绘制信息放入二维数组
        String[][] boardInfos = this.getBoardInfos();
        if(boardInfos[0][0] == null){
            for (int i=0; i<boardInfos.length; i++){
                for (int j=0; j< boardInfos[i].length; j++){
                    if(i == 0 && j ==0){
                        boardInfos[i][j] = " "; // 左上角空白处
                    }else if(i==0){
                        boardInfos[i][j] = Integer.toHexString(j-1); // 第一行
                    }else if(j==0){
                        boardInfos[i][j] = Integer.toHexString(i-1); // 第一列
                    }else{
                        boardInfos[i][j] = "+";
                    }
                }
            }
            this.setBoardInfos(boardInfos);
        }
        // 2.打印棋盘信息
        System.out.println("棋盘信息(B代表黑方棋子，W代表白方棋子)：");
        for (int i=0; i<boardInfos.length; i++){
            for (int j=0; j<boardInfos[i].length; j++){
                System.out.print(boardInfos[i][j] + "  ");
            }
            System.out.println();
        }
    }

    /**
     * 提示黑方和白方分别下棋并重新绘制棋盘
     */
    public void play(){
        // 1.获取棋盘信息
        String[][] boardInfos = this.getBoardInfos();
        // 2.假设黑方先下棋，轮流提示黑方和白方下棋
        String role = "B"; // B代表黑方下棋，W代表白方下棋，N代表结束本局下棋
        while (!"N".equals(role)){
            if("B".equals(role)){
                System.out.println("请黑方下棋（输入棋盘中的坐标，如：5 6，输入-1 -1表示结束本局下棋）：");
            }else if("W".equals(role)){
                System.out.println("请白方下棋（输入棋盘中的坐标，如：5 6，输入-1 -1表示结束本局下棋）：");
            }
            Scanner sc = new Scanner(System.in);
            String pattern = "0|1|2|3|4|5|6|7|8|9|a|b|c|d|e";
//            Pattern.matches(pattern, sc.next());
            String strX = sc.next();
            String strY = sc.next();
//            System.out.println("9999---- " + Pattern.matches(pattern, strX));
            // 将输入的坐标转换为十进制整数

//            System.out.println("x: " + x + ", y: "+ y);
            // 3.判断棋子下的位置是否合理
            if(!Pattern.matches(pattern, strX)){
                System.out.println("输入错误，请重新下棋！");
            }else{
                int x = Integer.parseInt(strX, 16);
                int y = Integer.parseInt(strY, 16);
                if(x == -1 && y == -1){
                    role = "N"; // 标记结束本局下棋
                    System.out.println("本局对弈结束！");
                }else if(!"+".equals(boardInfos[x+1][y+1])){
                    System.out.println("该位置已有棋子，请重新下！");
                }else {
                    // 2.更新棋盘信息,并标记该对方下棋
                    boardInfos[x+1][y+1] = role; // 把棋盘对应的位置标记该方已下的棋子
                    this.setBoardInfos(boardInfos);
                    // 3.重新绘制棋盘信息
                    this.drawBoard();
                    // 4.棋子落下后判断该方是否获胜，获胜则结束对弈，失败则提示该对方下棋
                    boolean judgeRes =  this.judge(role, x+1, y+1);
                    if(judgeRes){
                        System.out.println("恭喜" + ("B".equals(role)?"黑方":"白方") + "获得胜利！对弈结束！");
                        role = "N";
                    }else{
                        role = ("B".equals(role)?"W":"B"); // 轮换对方下棋
                    }
                }
            }
        }
    }

    /**
     * 判断是否获胜
     */
    public boolean judge(String role, int pointX, int pointY){
//        System.out.println("pointX: "+ pointX + ", pointY: " + pointY);
        // 1.获取棋盘信息
        String[][] boardInfos = this.getBoardInfos();
        // 2.判断是否成功
        for (int i=1; i<=5; i++){
            int sumNum = 0; // 记录连成的棋子数
            // a.判断竖方向是否成功连成五颗棋子
            // 该位置上下是否留下足够的5个棋子空间
            int startX = pointX - (i-1); // 5个棋子开始位置
            int endX = pointX + (5-i); // 5个棋子末位置
            if(startX>=1 && endX <= 16){
                for (int j= startX; j<=endX; j++){
                    if(role.equals(boardInfos[j][pointY])){
                        sumNum++;
                    }else{
                        break;
                    }
                }
                if(sumNum == 5){
                    // 连成5颗棋子，获得胜利，返回true
//                    System.out.println("恭喜" + ("B".equals(role)?"黑方":"白方") + "获得胜利！");
                    return true;
                }
            }
            // b.判断横方向是否成功连成五颗棋子
            // 该位置左右是否留下足够的5个棋子空间
            sumNum = 0;
            int startY = pointY - (i-1); // 5个棋子开始位置
            int endY = pointY + (5-i); // 5个棋子结束位置
//            System.out.println("startY: "+ startY + ", endY: " + endY);
            if(startY>=1 && endY<=16){
                for (int j=startY; j<=endY; j++){
                    if(role.equals(boardInfos[pointX][j])){
                        sumNum++;
                    }else {
                        break;
                    }
                }
//                System.out.println("sumNum = " + sumNum);
                if(sumNum == 5){
                    // 连成5颗棋子，获得胜利，返回true
                    return true;
                }
            }
            // c.判断左上到右下斜线方向是否成功连成五颗棋子
            sumNum = 0;
            // 5颗棋子起止位置
            startX = pointX - (i-1);
            endX = pointX + (5-i);
            startY = pointY - (i-1);
            endY = pointY + (5-i);
            if(startX>=1 && endX<=16 && startY>=1 && endY<=16){
                int k = startY;
                for (int j=startX; j<=endX; j++){
                    if(role.equals(boardInfos[j][k])){
                        sumNum++;
                    }else {
                        break;
                    }
                    k++;
                }
                // 连成5颗棋子，获得胜利，返回true
                if(sumNum == 5){
                    return true;
                }
            }
            // d.判断右上到左下斜线方向是否成功连成五颗棋子
            sumNum = 0;
            // 5颗棋子起止位置
            startX = pointX - (5-i);
            endX = pointX + (i-1);
            startY = pointY - (i-1);
            endY = pointY + (5-i);
            if(startX>=1 && endX<=16 && startY>=0 && endY<=16){
                int k = endY;
                for(int j=startX; j<=endX; j++){
                    if(role.equals(boardInfos[j][k])){
                        sumNum++;
                    }else{
                        break;
                    }
                    k--;
                }
                if(sumNum == 5){
                    // 连成5颗棋子，获得胜利，返回true
                    return true;
                }
            }
        }
        // 四个方向都未成功，返回false
        return false;
    }

    public static void main(String[] args) {

        GobangGame gobangGame = new GobangGame();
        // 游戏开始绘制棋盘信息
        gobangGame.drawBoard();
        // 开始五子棋游戏
        gobangGame.play();
    }
}
